home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / utility2 / ue312dev.zip / SRC / AMIGADOS.C next >
C/C++ Source or Header  |  1993-03-02  |  22KB  |  893 lines

  1. /*    AMIGADOS.C:    Operating specific I/O and Spawning functions
  2.             for MicroEMACS 3.12
  3.             (C)Copyright 1993 by Daniel M. Lawrence
  4. */
  5.  
  6. #include        <stdio.h>
  7. #include    "estruct.h"
  8. #if    AMIGA
  9. #include    <exec/types.h>
  10. #include    <exec/io.h>
  11. #include    <intuition/intuition.h>
  12. #include    <devices/console.h>
  13. #include    "eproto.h"
  14. #include        "edef.h"
  15. #include    "elang.h"
  16.  
  17. #define INTUITION_REV    0L
  18. #define    NEW         1006L
  19. #define    CRWIDTH        8
  20. #define    CRHEIGHT    8
  21.  
  22. struct IntuitionBase *IntuitionBase;
  23. struct Window *win;
  24. struct IOStdReq con;        /* ptr to console device driver handle */
  25.  
  26. /*    Intuition Function type declarations    */
  27.  
  28. struct IntuitionBase *OpenLibrary();
  29. struct Window *OpenWindow();
  30. struct IntuiMessage *GetMsg();
  31.  
  32. typedef struct {
  33.     short rw_code;        /* normal keycode to generate */
  34.     short rw_scode;        /* shifted  "  */
  35.     short rw_ccode;        /* control  "  */
  36. } RKEY;
  37.  
  38. /* raw keycode scan code to emacs keycode translation table */
  39.  
  40. RKEY keytrans[0x60] = {
  41.  
  42. /*    CODE    NORM    SHIFT    CTRL */
  43. /*    0x00,*/    '`',    '~',    0,
  44. /*    0x01,*/    '1',    '!',    0,
  45. /*    0x02,*/    '2',    '@',    0,
  46. /*    0x03,*/    '3',    '#',    0,
  47. /*    0x04,*/    '4',    '$',    0,
  48. /*    0x05,*/    '5',    '%',    0,
  49. /*    0x06,*/    '6',    '^',    0,
  50. /*    0x07,*/    '7',    '&',    0,
  51. /*    0x08,*/    '8',    '*',    0,    
  52. /*    0x09,*/    '9',    '(',    0,
  53. /*    0x0a,*/    '0',    ')',    0,
  54. /*    0x0b,*/    '-',    '_',    0,
  55. /*    0x0c,*/    '=',    '+',    0,
  56. /*    0x0d,*/    '\\',    '|',    0,
  57. /*    0x0e,*/    0,    0,    0,
  58. /*    0x0f,*/    0,    0,    0,
  59. /*    0x10,*/    'q',    'Q',    CTRL|'Q',
  60. /*    0x11,*/    'w',    'W',    CTRL|'W',
  61. /*    0x12,*/    'e',    'E',    CTRL|'E',
  62. /*    0x13,*/    'r',    'R',    CTRL|'R',
  63. /*    0x14,*/    't',    'T',    CTRL|'T',
  64. /*    0x15,*/    'y',    'Y',    CTRL|'Y',
  65. /*    0x16,*/    'u',    'U',    CTRL|'U',
  66. /*    0x17,*/    'i',    'I',    CTRL|'I',
  67. /*    0x18,*/    'o',    'O',    CTRL|'O',
  68. /*    0x19,*/    'p',    'P',    CTRL|'P',
  69. /*    0x1a,*/    '[',    '{',    0,
  70. /*    0x1b,*/    ']',    '}',    0,
  71. /*    0x1c,*/    0,    0,    0,
  72. /*    0x1d,*/    '1',    SPEC|'>',    0,
  73. /*    0x1e,*/    '2',    SPEC|'N',    0,
  74. /*    0x1f,*/    '3',    SPEC|'V',    0,
  75. /*    0x20,*/    'a',    'A',    CTRL|'A',
  76. /*    0x21,*/    's',    'S',    CTRL|'S',
  77. /*    0x22,*/    'd',    'D',    CTRL|'D',
  78. /*    0x23,*/    'f',    'F',    CTRL|'F',
  79. /*    0x24,*/    'g',    'G',    CTRL|'G',/*    0x25,*/    'h',    'H',    CTRL|'H',
  80. /*    0x26,*/    'j',    'J',    CTRL|'J',
  81. /*    0x27,*/    'k',    'K',    CTRL|'K',
  82. /*    0x28,*/    'l',    'L',    CTRL|'L',
  83. /*    0x29,*/    ';',    ':',    0,
  84. /*    0x2a,*/    39,    34,    0,
  85. /*    0x2b,*/    0,    0,    0,
  86. /*    0x2c,*/    0,    0,    0,
  87. /*    0x2d,*/    '4',    SPEC|'B',    0,
  88. /*    0x2e,*/    '5',    0,        0,
  89. /*    0x2f,*/    '6',    SPEC|'F',    0,
  90.     /* this key is probably mapped on forign AIMIGA keyboards */
  91. /*    0x30,*/    0,    0,    0,
  92. /*    0x31,*/    'z',    'Z',    CTRL|'Z',
  93. /*    0x32,*/    'x',    'X',    CTRL|'X',
  94. /*    0x33,*/    'c',    'C',    CTRL|'C',
  95. /*    0x34,*/    'v',    'V',    CTRL|'V',
  96. /*    0x35,*/    'b',    'B',    CTRL|'B',
  97. /*    0x36,*/    'n',    'N',    CTRL|'N',
  98. /*    0x37,*/    'm',    'M',    CTRL|'M',
  99. /*    0x38,*/    ',',    '<',    0,
  100. /*    0x39,*/    '.',    '>',    0,
  101. /*    0x3a,*/    '/',    '?',    0,
  102. /*    0x3b,*/    0,    0,    0,
  103. /*    0x3c,*/    '.',    SPEC|'D',    0,
  104. /*    0x3d,*/    '7',    SPEC|'<',    0,
  105. /*    0x3e,*/    '8',    SPEC|'P',    0,
  106. /*    0x3f,*/    '9',    SPEC|'Z',    0,
  107. /*    0x40,*/    ' ',    SHFT|' ',    0,
  108. /*    0x41,*/    CTRL|'H',    SHFT|'D',    0,
  109. /*    0x42,*/    CTRL|'I',    SHFT|'I',    0,
  110. /*    0x43,*/    CTRL|'M', CTRL|'M', CTRL|'M',
  111. /*    0x44,*/    CTRL|'M', CTRL|'M', CTRL|'M',
  112. /*    0x45,*/    CTRL|'[',    0,    0,
  113. /*    0x46,*/    SPEC|'D',    0,    0,
  114. /*    0x47,*/    0,    0,    0,
  115. /*    0x48,*/    0,    0,    0,
  116. /*    0x49,*/    0,    0,    0,
  117. /*    0x4a,*/    '-',    0,    0,
  118. /*    0x4b,*/    0,    0,    0,
  119. /*    0x4c,*/    SPEC|'P',    SHFT|SPEC|'P',    CTRL|SPEC|'P',
  120. /*    0x4d,*/    SPEC|'N',    SHFT|SPEC|'N',    CTRL|SPEC|'N',
  121. /*    0x4e,*/    SPEC|'F',    SHFT|SPEC|'F',    CTRL|SPEC|'F',
  122. /*    0x4f,*/    SPEC|'B',    SHFT|SPEC|'B',    CTRL|SPEC|'B',
  123. /*    0x50,*/    SPEC|'1',    SHFT|SPEC|'1',    CTRL|SPEC|'1',
  124. /*    0x51,*/    SPEC|'2',    SHFT|SPEC|'2',    CTRL|SPEC|'2',
  125. /*    0x52,*/    SPEC|'3',    SHFT|SPEC|'3',    CTRL|SPEC|'3',
  126. /*    0x53,*/    SPEC|'4',    SHFT|SPEC|'4',    CTRL|SPEC|'4',
  127. /*    0x54,*/    SPEC|'5',    SHFT|SPEC|'5',    CTRL|SPEC|'5',
  128. /*    0x55,*/    SPEC|'6',    SHFT|SPEC|'6',    CTRL|SPEC|'6',
  129. /*    0x56,*/    SPEC|'7',    SHFT|SPEC|'7',    CTRL|SPEC|'7',
  130. /*    0x57,*/    SPEC|'8',    SHFT|SPEC|'8',    CTRL|SPEC|'8',
  131. /*    0x58,*/    SPEC|'9',    SHFT|SPEC|'9',    CTRL|SPEC|'9',
  132. /*    0x59,*/    SPEC|'0',    SHFT|SPEC|'0',    CTRL|SPEC|'0',
  133. /*    0x5a,*/    '(',    0,    0,
  134. /*    0x5b,*/    ')',    0,    0,
  135. /*    0x5c,*/    '/',    0,    0,
  136. /*    0x5d,*/    '*',    0,    0,
  137. /*    0x5e,*/    0,    0,    0,
  138. /*    0x5f,*/    SPEC|'?',    0,    0,
  139. };
  140.  
  141. /* some keyboard keys current states */
  142.  
  143. int r_shiftflag;    /* right shift key */
  144. int l_shiftflag;    /* left shift key */
  145. int r_altflag;        /* right alt key */
  146. int l_altflag;        /* left alt key */
  147. int r_amiflag;        /* right amiga key */
  148. int l_amiflag;        /* left amiga key */
  149. int ctrlflag;        /* control key */
  150. int lockflag;        /* shift lock key */
  151.  
  152. /*    output buffers and pointers    */
  153.  
  154. #define OBUFSIZE    1024L
  155. #define    IBUFSIZE    64    /* this must be a power of 2 */
  156.  
  157. char out_buf[OBUFSIZE+1];    /* output character buffer */
  158. int out_ptr = 0;        /* index to next char to put in buffer */
  159.  
  160. /*    input buffers and pointers    */
  161.  
  162. #define    IBUFSIZE    64    /* this must be a power of 2 */
  163.  
  164. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  165. int in_next = 0;        /* pos to retrieve next input character */
  166. int in_last = 0;        /* pos to place most recent input character */
  167.  
  168. in_init()    /* initialize the input buffer */
  169.  
  170. {
  171.     in_next = in_last = 0;
  172. }
  173.  
  174. in_check()    /* is the input buffer non-empty? */
  175.  
  176. {
  177.     if (in_next == in_last)
  178.         return(FALSE);
  179.     else
  180.         return(TRUE);
  181. }
  182.  
  183. in_put(event)
  184.  
  185. int event;    /* event to enter into the input buffer */
  186.  
  187. {
  188.     in_buf[in_last++] = event;
  189.     in_last &= (IBUFSIZE - 1);
  190. }
  191.  
  192. int in_get()    /* get an event from the input buffer */
  193.  
  194. {
  195.     register int event;    /* event to return */
  196.  
  197.     event = in_buf[in_next++];
  198.     in_next &= (IBUFSIZE - 1);
  199.     return(event);
  200. }
  201.  
  202. /*
  203.  * This function is called once to set up the terminal device streams.
  204.  * On VMS, it translates TT until it finds the terminal, then assigns
  205.  * a channel to it and sets it raw. On CPM it is a no-op.
  206.  */
  207. ttopen()
  208. {
  209.     struct NewWindow new_win;
  210.     int i;
  211. #if    AZTEC
  212.     extern    Enable_Abort;    /* Turn off ctrl-C interrupt */
  213.  
  214.     Enable_Abort = 0;    /* for the Manx compiler */
  215. #endif
  216.     strcpy(os, "AMIGADOS");
  217.  
  218.     /* open the intuition library */
  219.     IntuitionBase = (struct IntuitionBase *)
  220.         OpenLibrary("intuition.library", INTUITION_REV);
  221.     if (IntuitionBase == NULL) {
  222.         printf("%%Can not open Intuition\n");
  223.         exit(-1);
  224.     }
  225.  
  226.     /* initialize the new windows attributes */
  227.     new_win.LeftEdge = 0;
  228.     new_win.TopEdge = 0;
  229.     new_win.Width = 640;
  230.     new_win.Height = 200;
  231.     new_win.DetailPen = 0;
  232.     new_win.BlockPen = 1;
  233.     new_win.Title = (unsigned char *)"MicroEMACS 3.12g/Amiga";
  234.     new_win.Flags = WINDOWCLOSE | SMART_REFRESH | ACTIVATE |
  235.         WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | SIZEBRIGHT |
  236.         RMBTRAP | NOCAREREFRESH;
  237.     new_win.IDCMPFlags = CLOSEWINDOW | NEWSIZE | MOUSEBUTTONS |
  238.         RAWKEY;
  239.     new_win.Type = WBENCHSCREEN;
  240.     new_win.FirstGadget = NULL;
  241.     new_win.CheckMark = NULL;
  242.     new_win.Screen = NULL;
  243.     new_win.BitMap = NULL;
  244.     new_win.MinWidth = 100;
  245.     new_win.MinHeight = 25;
  246.     new_win.MaxWidth = 640;
  247.     new_win.MaxHeight = 200;
  248.  
  249.     /* open the window! */
  250.     win = (struct Window *)OpenWindow(&new_win);
  251.     if (win == NULL) {
  252.         printf("%%Can not open a window\n");
  253.         exit(-2);
  254.     }
  255.  
  256.     /* and open up the console for output */
  257.     con.io_Data = (APTR)win;
  258.     OpenDevice("console.device", 0, &con, 0);
  259.  
  260.     /* and init all the keyboard flags */
  261.     r_shiftflag = FALSE;
  262.     l_shiftflag = FALSE;    r_altflag = FALSE;
  263.     l_altflag = FALSE;
  264.     r_amiflag = FALSE;
  265.     l_amiflag = FALSE;
  266.     ctrlflag = FALSE;
  267.     lockflag = FALSE;
  268.  
  269.     /* initialize our private event queue */
  270.     in_init();
  271.  
  272.     /* set the current sizes */
  273.     newwidth(TRUE, 77);
  274.     newsize(TRUE, 23);
  275.  
  276.     /* on all screens we are not sure of the initial position
  277.        of the cursor                    */
  278.     ttrow = 999;
  279.     ttcol = 999;
  280. }
  281.  
  282. /*
  283.  * This function gets called just before we go back home to the command
  284.  * interpreter. On VMS it puts the terminal back in a reasonable state.
  285.  * Another no-operation on CPM.
  286.  */
  287. ttclose()
  288.  
  289. {
  290.     /* make sure there is no pending output */
  291.     ttflush();
  292.  
  293.     /* and now close up shop */
  294.     CloseDevice(&con);
  295.     CloseWindow(win);
  296.     OpenWorkBench();
  297. }
  298.  
  299. /*
  300.  * Write a character to the display. On VMS, terminal output is buffered, and
  301.  * we just put the characters in the big array, after checking for overflow.
  302.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  303.  * MS-DOS (use the very very raw console output routine).
  304.  */
  305.  
  306. ttputc(c)
  307.  
  308. char c;
  309.  
  310. {
  311.     /* add the character to the output buffer */
  312.         out_buf[out_ptr++] = c;
  313.  
  314.         /* send the buffer out if we are at the limit */
  315.         if (out_ptr >= OBUFSIZE)
  316.                 ttflush();
  317. }
  318.  
  319. /*
  320.  * Flush terminal buffer. Does real work where the terminal output is buffered
  321.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  322.  */
  323.  
  324. ttflush()
  325.  
  326. {
  327.     /* if there are any characters waiting to display... */
  328.         if (out_ptr) {
  329.             out_buf[out_ptr] = 0;    /* terminate the buffer string */
  330.             sendcon(out_buf);    /* send them out */
  331.             out_ptr = 0;        /* and reset the buffer */
  332.     }
  333. }
  334.  
  335. /*
  336.  * Read a character from the terminal.
  337.  */
  338.  
  339. ttgetc()
  340.  
  341. {
  342.     /* make sure there is no pending output */
  343. nxtchr:    ttflush();
  344.  
  345.     /* if it is already buffered up, get it */
  346.     if (in_check())
  347.         return(in_get());
  348.  
  349.     /* process an INTUITION event (possibly loading the input buffer) */
  350.     doevent();
  351.     goto nxtchr;
  352. }
  353.  
  354. #if    TYPEAH
  355. /* typahead:    Check to see if any characters are already in the
  356.         keyboard buffer
  357. */
  358.  
  359. typahead()
  360.  
  361. {
  362. tcheck:    /* if type ahead is already pending... */
  363.     if (in_check())
  364.         return(TRUE);
  365.  
  366.     /* check the signal for IDCMP events pending */
  367.     if ((1 << win->UserPort->mp_SigBit) != 0)
  368.         return(TRUE);
  369.  
  370.     /* no event in queue... no typeahead ready */
  371.     return(FALSE);
  372. }
  373. #endif
  374.  
  375. doevent()
  376.  
  377. {
  378.     register int eventX, eventY;    /* local copies of the event info */
  379.     struct IntuiMessage *event;    /* current event to repond to */
  380.     ULONG class;    /* class of event */
  381.     USHORT code;    /* data code */
  382.     SHORT x,y;    /* mouse x/y position at time of event */
  383.     char buf[128];    /*temp buff*/
  384.  
  385.     /* wait for an event to occur */
  386.     Wait(1 << win->UserPort->mp_SigBit);
  387.  
  388.     /* get the event and parse it up */
  389.     while (event = GetMsg(win->UserPort)) {
  390.         class = event->Class;
  391.         code = event->Code;
  392.         eventX = event->MouseX;
  393.         eventY = event->MouseY;
  394.         ReplyMsg(event);
  395.  
  396.         /* a normal keystroke? */
  397.         if (class == RAWKEY) {            dokey(code);
  398.             continue;
  399.         }
  400.  
  401.         /* User clicked on the close gadget! */
  402.         if (class == CLOSEWINDOW) {
  403.             quit(FALSE, 0);
  404.             stuffibuf(255, 0, 0);    /* fake a char to force quit to work */
  405.         }
  406.  
  407.         /* resolve the mouse address (border adjusted) */
  408.         if (class == NEWSIZE) {
  409.             x = (win->Width - 5) / CRWIDTH;
  410.             y = (win->Height - 10) / CRHEIGHT;
  411.         } else {
  412.             x = (eventX - 5) / CRWIDTH;
  413.             y = (eventY - 10) / CRHEIGHT;
  414.         }
  415.         if (x > 77)
  416.             x = 77;
  417.         if (y > 23)
  418.             y = 23;
  419.  
  420.         /* are we resizing the window? */
  421.         if (class == NEWSIZE) {
  422.             stuffibuf(MOUS | '1', x, y);
  423.             continue;
  424.         }
  425.  
  426.         /* and lastly, a mouse button press */
  427.         switch (code) {
  428.             case 104:    stuffibuf(MOUS | mod('a'), x, y);
  429.                     break;
  430.             case 232:    stuffibuf(MOUS | mod('b'), x, y);
  431.                     break;
  432.             case 105:    stuffibuf(MOUS | mod('e'), x, y);
  433.                     break;
  434.             case 233:    stuffibuf(MOUS | mod('f'), x, y);
  435.                     break;
  436.         }
  437.     }
  438.     return;
  439. }
  440.  
  441. int mod(c)    /* modify a character by the current shift and control flags */
  442.  
  443. int c;        /* original character */
  444.  
  445. {
  446.     /* first apply the shift and control modifiers */
  447.     if (l_shiftflag || r_shiftflag || lockflag)
  448.         c -= 32;
  449.     if (ctrlflag)
  450.         c |= CTRL;
  451.     return(c);
  452. }
  453.  
  454. sendcon(buf)    /* send a string to the console */
  455.  
  456. char *buf;    /* buffer to write out */
  457.  
  458. {
  459.     /* initialize the IO request */
  460.     con.io_Data = (APTR)buf;
  461.     con.io_Length = strlen(buf);
  462.     con.io_Command = CMD_WRITE;
  463.  
  464.     /* and perform the I/O */
  465.     SendIO(&con);
  466. }
  467.  
  468.  
  469. /* process an incomming keyboard code */
  470.  
  471. dokey(code)
  472.  
  473. int code;    /* raw keycode to convert */
  474.  
  475. {
  476.     register int ekey;    /* translate emacs key */
  477.     register int dir;    /* key direction (up/down) */
  478.     char buf[NSTRING];
  479.  
  480.     /* decode the direction of the key */
  481.     dir = TRUE;
  482.     if (code > 127) {
  483.         code = code & 127;
  484.         dir = FALSE;
  485.     }
  486.  
  487.     /* process various shift keys */
  488.     if (code >= 0x60) {
  489.         switch (code) {
  490.  
  491.             case 0x60:    l_shiftflag = dir;    break;
  492.             case 0x61:    r_shiftflag = dir;    break;
  493.             case 0x62:    lockflag    = dir;    break;
  494.             case 0x63:    ctrlflag    = dir;    break;
  495.             case 0x64:    l_altflag   = dir;    break;
  496.             case 0x65:    r_altflag   = dir;    break;
  497.             case 0x66:    l_amiflag   = dir;    break;
  498.             case 0x67:    r_amiflag   = dir;    break;
  499.  
  500.         }
  501.         return;
  502.     }
  503.  
  504.     /* up keystrokes are ignored for the rest of these */
  505.     if (dir == FALSE)
  506.         return;
  507.  
  508.     /* first apply the shift and control modifiers */
  509.     if (ctrlflag)
  510.         ekey = keytrans[code].rw_ccode;
  511.     else if (l_shiftflag || r_shiftflag || lockflag)
  512.         ekey = keytrans[code].rw_scode;
  513.     else
  514.         ekey = keytrans[code].rw_code;
  515.  
  516.     /* now apply the ALTD modifier */
  517.     if (r_altflag || l_altflag)
  518.         ekey |= ALTD;
  519.  
  520.     /* apply the META prefix */
  521.     if (r_amiflag || l_amiflag) {
  522.         if ('a' <= ekey && ekey <= 'z')
  523.             ekey -= 32;
  524.         ekey |= META;
  525.     }
  526.  
  527.     /* and place it in the input buffer */
  528.     stuffibuf(ekey, 0, 0);
  529. }
  530.  
  531. stuffibuf(key, x, y)    /* stuff a key in the input buffer */
  532.  
  533. int key;    /* extended keystroke to remember */
  534. int x, y;    /* mouse position to record */
  535.  
  536. {
  537.     register int upper;    /* upper extended bits of key */
  538.  
  539.     /* split the extended keystroke */
  540.     upper = key >> 8;
  541.     key = key & 255;
  542.  
  543.     /* if it is JUST control... encode it in! */
  544.     if (upper == (CTRL >> 8)) {
  545.         in_put(key - 64);
  546.         return;
  547.     }
  548.  
  549.     /* if it is normal, just place it inqueue */
  550.     if (upper == 0) {
  551.         in_put(key);
  552.         return;
  553.     }
  554.  
  555.     /* queue up an extended escape sequence */
  556.     in_put(0);        /* escape indicator */
  557.     in_put(upper);        /* event type */
  558.     if (upper & (MOUS >> 8)) {
  559.         in_put(x);    /* x position */
  560.         in_put(y);    /* y position */
  561.     }
  562.     in_put(key);        /* event code */
  563.     return;
  564. }
  565.  
  566. /*
  567.  * Create a subjob with a copy of the command intrepreter in it. When the
  568.  * command interpreter exits, mark the screen as garbage so that you do a full
  569.  * repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
  570.  * Under some (unknown) condition, you don't get one free when DCL starts up.
  571.  */
  572. spawncli(f, n)
  573. {
  574.         long newcli;
  575.  
  576.     /* don't allow this command if restricted */
  577.     if (restflag)
  578.         return(resterr());
  579.  
  580.         mlwrite(TEXT1);
  581. /*              "[Starting new CLI]" */
  582.         sgarbf = TRUE;
  583.         Execute("NEWCLI \"CON:0/0/640/200/MicroEMACS Subprocess\"", 0L, 0L);
  584.         return(TRUE);
  585. }
  586.  
  587. /*
  588.  * Run a one-liner in a subjob. When the command returns, wait for a single
  589.  * character to be typed, then mark the screen as garbage so a full repaint is
  590.  * done. Bound to "C-X !".
  591.  */
  592. spawn(f, n)
  593. {
  594.         register int    s;
  595.         char            line[NLINE];
  596.  
  597.         long newcli;
  598.  
  599.     /* don't allow this command if restricted */
  600.     if (restflag)
  601.         return(resterr());
  602.  
  603.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  604.                 return (s);
  605.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  606.         Execute(line, 0L, newcli);
  607.         Close(newcli);
  608.         tgetc();     /* Pause.               */
  609.         sgarbf = TRUE;
  610.         return(TRUE);
  611. }
  612.  
  613. /*
  614.  * Run an external program with arguments. When it returns, wait for a single
  615.  * character to be typed, then mark the screen as garbage so a full repaint is
  616.  * done. Bound to "C-X $".
  617.  */
  618.  
  619. execprg(f, n)
  620.  
  621. {
  622.         register int    s;
  623.         char            line[NLINE];
  624.  
  625.         long newcli;
  626.  
  627.     /* don't allow this command if restricted */
  628.     if (restflag)
  629.         return(resterr());
  630.  
  631.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  632.                 return (s);
  633.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  634.         Execute(line, 0L, newcli);
  635.         Close(newcli);
  636.         tgetc();     /* Pause.               */
  637.         sgarbf = TRUE;
  638.         return(TRUE);
  639. }
  640.  
  641. /*
  642.  * Pipe a one line command into a window
  643.  * Bound to ^X @
  644.  */
  645. pipecmd(f, n)
  646. {
  647.         register int    s;    /* return status from CLI */
  648.     register WINDOW *wp;    /* pointer to new window */
  649.     register BUFFER *bp;    /* pointer to buffer to zot */
  650.         char    line[NLINE];    /* command line send to shell */
  651.     static char bname[] = "command";
  652.  
  653.     static char filnam[] = "ram:command";
  654.         long newcli;
  655.  
  656.     /* don't allow this command if restricted */
  657.     if (restflag)
  658.         return(resterr());
  659.  
  660.     /* get the command to pipe in */
  661.         if ((s=mlreply("@", line, NLINE)) != TRUE)
  662.                 return(s);
  663.  
  664.     /* get rid of the command output buffer if it exists */
  665.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  666.         /* try to make sure we are off screen */
  667.         wp = wheadp;
  668.         while (wp != NULL) {
  669.             if (wp->w_bufp == bp) {
  670.                 onlywind(FALSE, 1);
  671.                 break;
  672.             }
  673.             wp = wp->w_wndp;
  674.         }
  675.         if (zotbuf(bp) != TRUE)
  676.  
  677.             return(FALSE);
  678.     }
  679.  
  680.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  681.     strcat(line, " >");
  682.     strcat(line, filnam);
  683.         Execute(line, 0L, newcli);
  684.     s = TRUE;
  685.         Close(newcli);
  686.         sgarbf = TRUE;
  687.  
  688.     if (s != TRUE)
  689.         return(s);
  690.  
  691.     /* split the current window to make room for the command output */
  692.     if (splitwind(FALSE, 1) == FALSE)
  693.             return(FALSE);
  694.  
  695.     /* and read the stuff in */
  696.     if (getfile(filnam, FALSE) == FALSE)
  697.         return(FALSE);
  698.  
  699.     /* make this window in VIEW mode, update all mode lines */
  700.     curwp->w_bufp->b_mode |= MDVIEW;
  701.     wp = wheadp;
  702.     while (wp != NULL) {
  703.         wp->w_flag |= WFMODE;
  704.         wp = wp->w_wndp;
  705.     }
  706.  
  707.     /* and get rid of the temporary file */
  708.     unlink(filnam);
  709.     return(TRUE);
  710. }
  711.  
  712. /*
  713.  * filter a buffer through an external DOS program
  714.  * Bound to ^X #
  715.  */
  716. filter(f, n)
  717.  
  718. {
  719.         register int    s;    /* return status from CLI */
  720.     register BUFFER *bp;    /* pointer to buffer to zot */
  721.         char line[NLINE];    /* command line send to shell */
  722.     char tmpnam[NFILEN];    /* place to store real file name */
  723.     static char bname1[] = "fltinp";
  724.  
  725.     static char filnam1[] = "ram:fltinp";
  726.     static char filnam2[] = "ram:fltout";
  727.         long newcli;
  728.  
  729.     /* don't allow this command if restricted */
  730.     if (restflag)
  731.         return(resterr());
  732.  
  733.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  734.         return(rdonly());    /* we are in read only mode    */
  735.  
  736.     /* get the filter name and its args */
  737.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  738.                 return(s);
  739.  
  740.     /* setup the proper file names */
  741.     bp = curbp;
  742.     strcpy(tmpnam, bp->b_fname);    /* save the original name */
  743.     strcpy(bp->b_fname, bname1);    /* set it to our new one */
  744.  
  745.     /* write it out, checking for errors */
  746.     if (writeout(filnam1, "w") != TRUE) {
  747.         mlwrite(TEXT2);
  748. /*                      "[Cannot write filter file]" */
  749.         strcpy(bp->b_fname, tmpnam);
  750.         return(FALSE);
  751.     }
  752.  
  753.         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
  754.     strcat(line, " <ram:fltinp >ram:fltout");
  755.         Execute(line,0L,newcli);
  756.     s = TRUE;
  757.         Close(newcli);
  758.         sgarbf = TRUE;
  759.  
  760.     /* on failure, escape gracefully */
  761.     if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  762.         mlwrite(TEXT3);
  763. /*                      "[Execution failed]" */
  764.         strcpy(bp->b_fname, tmpnam);
  765.         unlink(filnam1);
  766.         unlink(filnam2);
  767.         return(s);
  768.     }
  769.  
  770.     /* reset file name */
  771.     strcpy(bp->b_fname, tmpnam);    /* restore name */
  772.     bp->b_flag |= BFCHG;        /* flag it as changed */
  773.  
  774.     /* and get rid of the temporary file */
  775.     unlink(filnam1);
  776.     unlink(filnam2);
  777.     return(TRUE);
  778. }
  779.  
  780. /* return a system dependant string with the current time */
  781.  
  782. char *PASCAL NEAR timeset()
  783.  
  784. {
  785.     return(errorm);
  786. }
  787.  
  788. #if    AZTEC
  789. /*    FILE Directory routines        */
  790.  
  791. char path[NFILEN];    /* path of file to find */
  792. char rbuf[NFILEN];    /* return file buffer */
  793. extern char *scdir();
  794.  
  795. /*    do a wild card directory search (for file name completion) */
  796.  
  797. char *PASCAL NEAR getffile(fspec)
  798.  
  799. char *fspec;    /* pattern to match */
  800.  
  801. {
  802.     register int index;        /* index into various strings */
  803.     char fname[NFILEN];        /* file/path for DOS call */
  804.  
  805.     /* first parse the file path off the file spec */
  806.     strcpy(path, fspec);
  807.     index = strlen(path) - 1;
  808.     while (index >= 0 && (path[index] != '/' &&
  809.                 path[index] != '\\' && path[index] != ':'))
  810.         --index;
  811.     path[index+1] = 0;
  812.  
  813.     /* construct the composite wild card spec */
  814.     strcpy(fname, path);
  815.     strcat(fname, &fspec[index+1]);
  816.     strcat(fname, "*.*");
  817.  
  818.     /* save the path/wildcard off */
  819.     strcpy(path, fname);
  820.  
  821.     /* and call for the first file */
  822.     return(getnfile());
  823. }
  824.  
  825. char *PASCAL NEAR getnfile()
  826.  
  827. {
  828.     register char *sp;    /* return from scdir */
  829.  
  830.     /* and call for the next file */
  831.     sp = scdir(path);
  832.     if (sp == NULL)
  833.         return(NULL);
  834.  
  835.     /* return the next file name! */
  836.     strcpy(rbuf, sp);
  837.     return(rbuf);
  838. }
  839. #else
  840. char *PASCAL NEAR getffile(fspec)
  841.  
  842. char *fspec;    /* file to match */
  843.  
  844. {
  845.     return(NULL);
  846. }
  847.  
  848. char *PASCAL NEAR getnfile()
  849.  
  850. {
  851.     return(NULL);
  852. }
  853. #endif
  854.  
  855. #if    AZTEC
  856.  
  857. /*    Big flame..... AZTEC C documents, but seems to be missing the
  858.     standard library realloc() function.  A quick replacement is
  859.     below.  Note that this ALWAYS copies to a new block, and is
  860.     thus inherently less efficient than a native one would be.
  861. */
  862.  
  863. char *realloc(ptr, size)
  864.  
  865. char *ptr;    /* original pointer */
  866. int size;    /* # of bytes for newly allocated block */
  867.  
  868. {
  869.     char *src, *dest;    /* ptrs for byte copying */
  870.     char *nptr;        /* newly allocated pointer */
  871.  
  872.     /* allocate the new memory block */
  873.     nptr = malloc(size);
  874.     if (nptr == NULL)
  875.         return(NULL);
  876.  
  877.     /* copy the bytes from the old one */
  878.     src = ptr;
  879.     dest = nptr;
  880.     while (size--)
  881.         *dest++ = *src++;
  882.  
  883.     /* and free the old one */
  884.     free(ptr);
  885.     return(nptr);
  886. }
  887.  
  888. #else
  889. adoshello()
  890. {
  891. }
  892. #endif
  893.